package aes

import (
	"crypto/aes"
	"crypto/cipher"
	"fmt"
	"github.com/pkg/errors"
)

type CryptoOFB struct {
	block cipher.Block
	iv    []byte
	key   []byte
	way   Way
}

func newAESCryptoOFB(key, iv []byte, way Way) (Crypto, error) {
	b, err := aes.NewCipher(key)

	if err != nil {
		return nil, err
	}

	r := &CryptoOFB{
		block: b,
		iv:    iv,
		key:   key,
		way:   way,
	}

	return r, nil
}

func (a *CryptoOFB) Encrypt(plainText []byte) (cipherText []byte, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = errors.Wrap(errors.New("aes ofb encrypt error"), fmt.Sprintf("%+v", e))
			return
		}
	}()

	cipherText = make([]byte, len(plainText))
	crypto := cipher.NewOFB(a.block, a.iv)
	crypto.XORKeyStream(cipherText, plainText)

	return Encode(cipherText, a.way), nil
}

func (a *CryptoOFB) Decrypt(cipherText []byte) (plainText []byte, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = errors.Wrap(errors.New("aes ofb decrypt error"), fmt.Sprintf("%+v", e))
			return
		}
	}()

	cipherText, err = Decode(cipherText, a.way)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	plainText = make([]byte, len(cipherText))
	crypto := cipher.NewOFB(a.block, a.iv)
	crypto.XORKeyStream(plainText, cipherText)
	return plainText, nil
}
